iT邦幫忙

2026 iThome 鐵人賽

DAY 14
0
Security

30 天實戰車聯網資安系列 第 14

Day 14|SUMO 實作:建立第一個交通模擬場景

  • 分享至 

  • xImage
  •  

Day 13 我們用 netgenerate 快速產生格狀道路,再透過 SUMO GUI 看見第一座會跑車的城市。

這種方式很適合確認環境是否正常,但工具自動產生的路網藏了不少細節。

如果今天想研究智慧十字路口,就必須能回答下面幾個問題:

  • 路口座標在哪裡?
  • 道路允許往哪個方向行駛?
  • 車輛要走過哪些道路?
  • 一段時間內會出現多少車?
  • 模擬結束後要用什麼資料判斷交通狀況?

今天我們不再讓工具替我們決定整座城市,而是從八個 Node 與十四條 Edge 開始,親手建立一條具有兩座號誌路口的城市幹道。

接著會加入一台指定車輛與六股車流,最後輸出 TripInfo 檢查每台車的行程時間及等待狀況。

完成基本場景後,我們還會把相同需求放大成兩倍,做一次正常車流與尖峰車流的對照實驗。

今天的學習目標

讀完這篇文章,你應該能夠:

  1. 分辨 Plain XML 與 .net.xml 的用途
  2. 使用 Node 與 Edge 描述一條雙路口城市幹道
  3. 使用 netconvert 產生 SUMO Network
  4. 使用 Route 定義車輛的行駛路徑
  5. 分辨 Vehicle 與 Flow 的差異
  6. 使用 .sumocfg 載入路網及交通需求
  7. 透過 SUMO GUI 與 TripInfo 驗證模擬結果
  8. 比較正常車流與兩倍車流的等待時間及時間損失

今天要建立什麼場景?

我們要建立一條東西向城市幹道,途中會經過 j1j2 兩座號誌路口。

兩座路口各自連接南北向支路,車輛除了直行穿越幹道,也能從支路轉入主要道路。

               north_j1                 north_j2
                   │                        │
                   │                        │
west ───────────── j1 ──────────────────── j2 ───────────── east
                   │                        │
                   │                        │
               south_j1                 south_j2

東西向幹道長 900 公尺,兩座路口相距 300 公尺。

這個規模仍然容易閱讀 XML,卻已經能觀察連續號誌、支路匯入與車流累積,不會只是把 Day 13 的城市縮成一個小路口。

整個實作會經過以下流程:

day14.nod.xml + day14.edg.xml
                 │
                 ▼
             netconvert
                 │
                 ▼
           day14.net.xml
                 │
                 ├── day14.rou.xml
                 └── day14.sumocfg
                         │
                         ▼
                   sumo/sumo-gui
                         │
                         ▼
          day14-tripinfo.xml/day14-summary.xml

其中 day14.nod.xmlday14.edg.xml 是方便人類編輯的 Plain XML。

netconvert 會把它們轉成 SUMO 能直接載入的 day14.net.xml,並補上 Lane、Connection 與 Junction Logic 等衍生資料。

.net.xml 不是這次要手動維護的原始檔。需要調整路口或道路時,應修改 Node/Edge 檔案後重新執行 netconvert

SUMO 官方教學也會先用 Node 與 Link 的方式規劃路網,再加入車輛類型、路線及交通需求。

SUMO 官方 Quick Start 使用 Node 與 Link 規劃交通模擬路網

圖 1:SUMO 路網可以先用 Node 與具有方向的道路區段描述,圖中的官方範例同樣包含連續路口與支路
圖片來源: Eclipse SUMO Documentation

Node、Edge 與 Route 的關係

開始寫檔案前,先把三個最容易混淆的概念分開。

元件 代表什麼 今天的例子
Node 道路端點或路口 j1j2west
Edge 兩個 Node 之間具有方向的道路 west_j1
Route 車輛依序通過的 Edge west_j1 j1_j2 j2_east

一條 Edge 只有一個方向。

因此,西邊通往第一座路口與第一座路口通往西邊是兩條不同的 Edge:

west → j1    west_j1
j1 → west    j1_west

Route 則必須由前後相連的 Edge 組成。

例如從西向東通過兩座路口,可以寫成:

west_j1 → j1_j2 → j2_east

如果把兩條沒有相接的 Edge 放進同一條 Route,SUMO 就無法替車輛建立連續路徑。

為什麼加入兩座號誌路口?

單一路口可以用來認識 Node 與 Edge,但連續路口才容易看見號誌之間的影響。

一台車通過 j1 後,可能在抵達 j2 時再次遇到紅燈,後方車流也可能逐漸在兩座路口之間累積。

今天先讓 netconvert 自動建立固定週期的號誌邏輯,不另外手寫 <tlLogic>

這些預設號誌適合教學與基礎測試,但不代表任何真實城市的號誌時制,也沒有根據實際交通量完成最佳化。

兩座號誌預設各自運作,尚未建立綠波協調。

因此,我們可以在 GUI 觀察 demo_car 能否連續通過,並利用 TripInfo 看見等待如何反映在 durationtimeLoss

Vehicle 與 Flow 有什麼不同?

vehicle 用來描述一台明確的車。

它有自己的 ID、出發時間、車輛類型及路線,很適合控制特定測試節點。

flow 則描述一段時間內持續產生的交通需求。

它可以使用固定間隔、每小時流率或車輛總數,不需要逐台列出 Vehicle。

需求類型 適合使用的情境 今天的用途
Vehicle 追蹤指定車輛或安排精確出發時間 建立紅色的 demo_car
Flow 建立背景車流或大量交通需求 產生幹道與支路的六股持續車流

到了後面的 V2X 攻擊模擬,我們可以把惡意車輛寫成單獨的 Vehicle,再用 Flow 產生正常背景車流。

這樣能控制攻擊節點何時出現,也不必逐台建立其他道路使用者。

今日實作:手動建立一條雙路口城市幹道

本次實作在 Kali VM 進行,並沿用 Day 13 已安裝完成的 SUMO 環境。

如果下面任何一步出現錯誤,先不要直接修改產生後的 .net.xml,應回到對應的 Node、Edge 或 Route 檔案檢查。

步驟 1:建立工作目錄

開啟 Terminal 後執行:

mkdir -p ~/sumo-day14
cd ~/sumo-day14

後續建立的所有檔案都放在這個目錄,避免和 Day 13 的場景混在一起。

步驟 2:建立八個 Node

使用文字編輯器建立 day14.nod.xml

nano day14.nod.xml

填入以下內容:

<?xml version="1.0" encoding="UTF-8"?>
<nodes>
    <node id="j1" x="0" y="0" type="traffic_light"/>
    <node id="j2" x="300" y="0" type="traffic_light"/>

    <node id="west" x="-300" y="0"/>
    <node id="east" x="600" y="0"/>

    <node id="north_j1" x="0" y="200"/>
    <node id="south_j1" x="0" y="-200"/>
    <node id="north_j2" x="300" y="200"/>
    <node id="south_j2" x="300" y="-200"/>
</nodes>

座標單位是公尺。

j1 位於原點,j2 在東側 300 公尺處,幹道兩端再各延伸 300 公尺。

兩個路口都使用 type="traffic_light"netconvert 會替它們建立可使用的預設號誌邏輯。

步驟 3:建立十四條單向 Edge

建立 day14.edg.xml

nano day14.edg.xml

填入以下內容:

<?xml version="1.0" encoding="UTF-8"?>
<edges>
    <edge id="west_j1" from="west" to="j1"
          priority="2" numLanes="1" speed="13.89"/>
    <edge id="j1_west" from="j1" to="west"
          priority="2" numLanes="1" speed="13.89"/>
    <edge id="j1_j2" from="j1" to="j2"
          priority="2" numLanes="1" speed="13.89"/>
    <edge id="j2_j1" from="j2" to="j1"
          priority="2" numLanes="1" speed="13.89"/>
    <edge id="j2_east" from="j2" to="east"
          priority="2" numLanes="1" speed="13.89"/>
    <edge id="east_j2" from="east" to="j2"
          priority="2" numLanes="1" speed="13.89"/>

    <edge id="north_j1_in" from="north_j1" to="j1"
          priority="1" numLanes="1" speed="13.89"/>
    <edge id="j1_south_out" from="j1" to="south_j1"
          priority="1" numLanes="1" speed="13.89"/>
    <edge id="south_j1_in" from="south_j1" to="j1"
          priority="1" numLanes="1" speed="13.89"/>
    <edge id="j1_north_out" from="j1" to="north_j1"
          priority="1" numLanes="1" speed="13.89"/>

    <edge id="north_j2_in" from="north_j2" to="j2"
          priority="1" numLanes="1" speed="13.89"/>
    <edge id="j2_south_out" from="j2" to="south_j2"
          priority="1" numLanes="1" speed="13.89"/>
    <edge id="south_j2_in" from="south_j2" to="j2"
          priority="1" numLanes="1" speed="13.89"/>
    <edge id="j2_north_out" from="j2" to="north_j2"
          priority="1" numLanes="1" speed="13.89"/>
</edges>

每條 Edge 都只有一條 Lane,允許速度是每秒 13.89 公尺,約等於每小時 50 公里。

東西向 Edge 的 priority 設為 2,南北向支路則設為 1。

這個數值用來表示相對優先順序,不是車輛通過路口的保證,也不是資安風險分數。

步驟 4:使用 netconvert 產生 Network

執行:

netconvert \
  --node-files day14.nod.xml \
  --edge-files day14.edg.xml \
  --output-file day14.net.xml

成功時應該看到:

Success.

接著確認檔案已經產生:

ls -lh day14.nod.xml day14.edg.xml day14.net.xml

Kali Terminal 顯示 netconvert 成功產生 Day 14 路網檔案

圖 2:使用 netconvert 產生 day14.net.xml,並確認 Node、Edge 與 Network 檔案存在

如果出現 Unknown node,通常是 Edge 引用的 Node ID 拼錯。

如果出現連接相關錯誤,則要檢查 Edge 的 fromto 是否能在 j1j2 接起來。

步驟 5:先在 GUI 檢查空路網

在加入車輛之前先確認路網形狀:

sumo-gui -n day14.net.xml

畫面應該會出現一條連接兩座號誌路口的東西向幹道。

此時沒有任何車輛是正常現象,因為我們還沒加入 Route、Vehicle 或 Flow。

SUMO GUI 顯示尚未加入車流的雙路口城市幹道

圖 3:載入 day14.net.xml 後,SUMO GUI 顯示兩座號誌路口與東西向幹道

步驟 6:加入 Vehicle Type 與六條 Route

建立 day14.rou.xml

nano day14.rou.xml

填入以下內容:

<?xml version="1.0" encoding="UTF-8"?>
<routes>
    <vType id="passenger"
           vClass="passenger"
           accel="2.6"
           decel="4.5"
           sigma="0.5"
           length="5"
           maxSpeed="13.89"/>

    <route id="west_to_east"
           edges="west_j1 j1_j2 j2_east"/>
    <route id="east_to_west"
           edges="east_j2 j2_j1 j1_west"/>
    <route id="north1_to_south1"
           edges="north_j1_in j1_south_out"/>
    <route id="south1_to_east"
           edges="south_j1_in j1_j2 j2_east"/>
    <route id="north2_to_south2"
           edges="north_j2_in j2_south_out"/>
    <route id="south2_to_west"
           edges="south_j2_in j2_j1 j1_west"/>

    <vehicle id="demo_car"
             type="passenger"
             route="west_to_east"
             depart="0"
             color="1,0,0"/>

    <flow id="flow_we"
          type="passenger"
          route="west_to_east"
          begin="5" end="120" period="6"
          departLane="best" departSpeed="max"/>
    <flow id="flow_ew"
          type="passenger"
          route="east_to_west"
          begin="6" end="120" period="8"
          departLane="best" departSpeed="max"/>
    <flow id="flow_ns"
          type="passenger"
          route="north1_to_south1"
          begin="7" end="120" period="12"
          departLane="best" departSpeed="max"/>
    <flow id="flow_se"
          type="passenger"
          route="south1_to_east"
          begin="8" end="120" period="15"
          departLane="best" departSpeed="max"/>
    <flow id="flow_n2s2"
          type="passenger"
          route="north2_to_south2"
          begin="9" end="120" period="12"
          departLane="best" departSpeed="max"/>
    <flow id="flow_s2w"
          type="passenger"
          route="south2_to_west"
          begin="10" end="120" period="15"
          departLane="best" departSpeed="max"/>
</routes>

demo_car 會在第 0 秒從西側出發,並沿 west_to_east 依序通過兩座路口。

它被指定為紅色,方便之後在 GUI 裡追蹤。

六個 Flow 包含東西向幹道車流、穿越支路的直行車流,以及從南側支路匯入幹道的轉向車流。

例如 period="6" 表示這個 Flow 嘗試每 6 秒產生一台車,但實際進入時間仍可能受到道路空間影響。

Route 檔案中的 Vehicle 與 Flow 應依 departbegin 時間排列,這能避免載入需求時發生順序問題。

步驟 7:建立模擬設定檔

建立 day14.sumocfg

nano day14.sumocfg

填入以下內容:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <input>
        <net-file value="day14.net.xml"/>
        <route-files value="day14.rou.xml"/>
    </input>

    <time>
        <begin value="0"/>
        <end value="240"/>
    </time>

    <output>
        <tripinfo-output value="day14-tripinfo.xml"/>
        <summary-output value="day14-summary.xml"/>
    </output>
</configuration>

Flow 會在第 120 秒停止產生車輛,模擬則持續到第 240 秒。

多出的時間可以讓較晚出發的車繼續完成行程,減少模擬結束時仍停留在路網上的車輛。

步驟 8:先用命令列驗證場景

執行:

sumo -c day14.sumocfg

命令正常結束後,確認輸出檔案:

ls -lh day14-tripinfo.xml day14-summary.xml

若 Route 無法連接,SUMO 會直接指出有問題的 Vehicle、Flow 或 Edge。

先在命令列排除設定錯誤,通常比只盯著 GUI 更容易找到原因。

步驟 9:在 GUI 觀察雙路口車流

執行:

sumo-gui -c day14.sumocfg

按下綠色播放按鈕後,應該會看到車輛沿幹道通過兩座號誌,也會有車輛從四條支路進入場景。

如果模擬瞬間結束,可以把上方的 Delay 調整到 100 或 200 ms,再重新執行一次。

觀察時可以特別注意:

  • 紅色 demo_car 是否從西向東行駛
  • demo_car 是否依序通過 j1j2
  • 號誌變換時,路口前方是否逐漸累積車輛
  • 支路車輛是否能直行或轉入東西向幹道
  • 車輛 ID 是否由 Flow 自動產生

SUMO GUI 正在執行雙路口城市幹道車流

圖 4:載入交通需求後,車輛沿幹道通過兩座號誌路口

步驟 10:查看 TripInfo

模擬完成後執行:

grep -m 5 '<tripinfo ' day14-tripinfo.xml

每一筆 <tripinfo> 代表一台已輸出行程資料的車輛,常見欄位包括:

欄位 代表意義
depart 車輛實際進入模擬的時間
arrival 車輛抵達終點的時間
duration 從出發到抵達所花的時間
waitingTime 車速低於等待門檻的累積時間
timeLoss 相對理想行駛狀況損失的時間
departDelay 原定出發與實際出發之間的延遲

接著查看 Summary:

grep -m 5 '<step ' day14-summary.xml

Summary 會按模擬時間記錄路網中的車輛數、平均速度與等待狀況,適合觀察整體趨勢。

TripInfo 則適合分析單一車輛或比較不同 Route 的行程表現。

Kali Terminal 顯示 day14 Summary 輸出

圖 5:從 day14-summary.xml 讀取各模擬時間點的車輛統計

步驟 11:比較正常車流與兩倍尖峰車流

目前我們已經有一組可正常執行的場景,接下來把它當成 Baseline(基準組)

這次只改變交通需求規模,路網、Route、車輛類型與模擬時間全部保持不變。

先執行正常車流:

sumo -c day14.sumocfg \
  --scale 1 \
  --tripinfo-output day14-baseline-tripinfo.xml \
  --summary-output day14-baseline-summary.xml \
  --statistic-output day14-baseline-statistics.xml \
  --tripinfo-output.write-unfinished true \
  --duration-log.statistics

再把需求放大為兩倍:

sumo -c day14.sumocfg \
  --scale 2 \
  --tripinfo-output day14-busy-tripinfo.xml \
  --summary-output day14-busy-summary.xml \
  --statistic-output day14-busy-statistics.xml \
  --tripinfo-output.write-unfinished true \
  --duration-log.statistics

--scale 2 會把載入的交通需求放大為兩倍,SUMO 會依需求內容增加 Vehicle 或提高 Flow 的產生頻率。

這裡沒有修改任何 XML,因此兩次執行的唯一主要變因就是交通量。

--tripinfo-output.write-unfinished true 會把模擬結束時尚未完成行程的車輛也納入輸出,避免壅塞組只統計已抵達的車輛而低估影響。

執行完成後查看兩組整體統計:

grep -H '<vehicleTripStatistics ' day14-*-statistics.xml

特別比較下面幾個欄位:

欄位 比較問題
count 兩組有多少車輛被納入統計?
duration 平均完成一趟行程需要多久?
waitingTime 車輛平均靜止等待多久?
timeLoss 相對理想行駛狀態損失多少時間?
departDelay 車輛是否因入口空間不足而延後出發?

我們可以先提出假設:

當其他條件保持不變,兩倍車流會讓兩座路口的競爭增加,因此平均等待時間與 Time Loss 可能上升。

實際數值仍取決於車流是否超過路口可以消化的程度。

如果兩組差異很小,可以把 --scale 2 改成 --scale 3 再執行一次,但要在實驗紀錄中清楚寫下調整後的倍率。

也可以在 SUMO GUI 上方把 Scale Traffic 設成 2,直接觀察車輛增加後的畫面。

不過正式比較仍建議使用命令列,因為指令能完整記錄實驗參數,也比較容易重現。

Kali Terminal 對照正常車流與兩倍車流的 vehicleTripStatistics

圖 6:比較 Baseline 與兩倍車流的車輛數、平均速度、等待時間及時間損失

怎麼確認今天的場景真的完成?

工作目錄中至少應該有以下檔案:

檔案 角色
day14.nod.xml 八個 Node 的座標與兩座號誌路口
day14.edg.xml 十四條單向 Edge 的道路設定
day14.net.xml netconvert 產生的完整 Network
day14.rou.xml Vehicle Type、Route、Vehicle 與 Flow
day14.sumocfg 模擬輸入、時間及輸出設定
day14-tripinfo.xml 每台車的行程結果
day14-summary.xml 各時間點的整體模擬摘要
day14-baseline-statistics.xml 正常車流的整體統計
day14-busy-statistics.xml 兩倍車流的整體統計

也可以用以下指令一次確認:

ls -1 day14.* day14-*.xml

今天的完成標準不是「GUI 裡看得到車」而已。

一個可重現的場景還要能從原始 Node/Edge 重新產生 Network,能從設定檔重跑相同交通需求,也能留下可分析的輸出資料。

從交通模擬走向車聯網資安

這條雙路口幹道目前只處理交通行為,還沒有任何 V2X 封包。

但它已經建立後續研究需要的基準環境:

路網
  → 限定車輛可以移動的空間

Route/Flow
  → 決定正常交通需求

Vehicle
  → 可指定為一般車輛或惡意節點

TripInfo/Summary
  → 衡量等待時間與交通影響

未來模擬假道路事件或錯誤位置訊息時,可以先保留相同路網與車流,建立沒有攻擊的 Baseline。

接著只改變攻擊情境與防護機制,再比較行程時間、等待狀況或車輛行為。

如果每次實驗同時更換路網、交通需求及攻擊參數,就很難判斷結果究竟由哪一項改變造成。

因此,今天這些看似普通的 XML 檔案,其實也是後續實驗設計與可重現性的基礎。

今日重點

  • Plain XML 適合描述 Node 與 Edge,再由 netconvert 產生 .net.xml
  • Edge 具有方向,雙向道路需要建立兩條方向相反的 Edge
  • Route 是一串前後相連的 Edge
  • traffic_light 類型可以讓 netconvert 產生預設號誌邏輯
  • Vehicle 適合控制單一車輛,Flow 適合建立持續交通需求
  • .sumocfg 讓命令列與 GUI 使用同一組模擬設定
  • TripInfo 用來分析單車行程,Summary 用來觀察整體模擬趨勢
  • --scale 可以在不修改 Route File 的情況下調整整體交通需求
  • Baseline 與尖峰組只改變一項主要變因,結果才有明確的比較基礎
  • 可重現的 Baseline 是後續比較 V2X 攻擊與防護結果的基礎

明日預告

今天完成了道路、車流與交通輸出,但 SUMO 仍然沒有處理任何無線封包。

Day 15 將進入 OMNeT++,認識離散事件模擬、Module、Network 與 Message,並回答車聯網研究為什麼需要另一套網路模擬器。

參考資料


上一篇
Day 13|SUMO 入門:用軟體建立一座會跑車的城市
下一篇
Day 15|OMNeT++ 入門:車聯網研究為什麼需要網路模擬器?
系列文
30 天實戰車聯網資安22
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言